package com.disney.domain.sdk.factory;

import com.disney.domain.sdk.anno.AbsBiz;
import com.disney.domain.sdk.anno.Biz;
import com.disney.domain.sdk.anno.FactorySpecs;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.reflections.Reflections;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * check该路径下，实现顶级接口IDomainBiz的所有抽象类应该标注@SubBiz注解，所有的类应该标注@Biz
 *
 * @author issavior
 */
public class FactoryImport implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // todo 这里获取到注解路径，扫描所有相关类，做check
        checkFactory(importingClassMetadata);

        return StringUtils.toStringArray(Lists.newArrayList());
    }

    private void checkFactory(AnnotationMetadata metadata) {

        Optional.ofNullable(metadata.getAnnotationAttributes(FactorySpecs.class.getName()))
                .filter(map -> (boolean) map.get("enable")).ifPresent(map -> {

                    ArrayList<String> paths = Optional.of(Lists.newArrayList((String[]) map.get("value"))).orElse(Lists.newArrayList(metadata.getClassName()));

                    // todo 将每个路径实现了接口的类，扫描，没有指定注解的，需要报错，并提示。
                    List<Class<? extends IDomainBiz>> classOrAbstract = paths.stream()
                            .flatMap(p ->
                                    Optional.ofNullable(new Reflections(p).getSubTypesOf(IDomainBiz.class))
                                            .orElse(Sets.newHashSet())
                                            .stream().filter(extFacadeClazz -> !extFacadeClazz.isInterface())
                            ).collect(Collectors.toList());

                    classOrAbstract.stream().filter(abs -> Modifier.isAbstract(abs.getModifiers()))
                            .filter(biz -> biz.getAnnotationsByType(AbsBiz.class).length != 1)
                            .filter(biz -> biz.getAnnotationsByType(AbsBiz.class).length == 0 || biz.getAnnotationsByType(AbsBiz.class)[0].value() == null)
                            .findFirst()
                            .ifPresent(FactoryImport::absSpecs);

                    classOrAbstract.stream()
                            .filter(abs -> !Modifier.isAbstract(abs.getModifiers()))
                            .filter(subBiz -> subBiz.getAnnotationsByType(Biz.class).length != 1)
                            .filter(subBiz -> subBiz.getAnnotationsByType(Biz.class).length == 0 || subBiz.getAnnotationsByType(Biz.class)[0].value() == null)
                            .findFirst()
                            .ifPresent(FactoryImport::classSpecs);

                });

    }

    private static void absSpecs(Class<? extends IDomainBiz> aClass) {
        throw new RuntimeException("根据领域工厂的使用规范，您的编码出现错误，错误如下:接口异常" + aClass);
    }

    private static void classSpecs(Class<? extends IDomainBiz> aClass) {
        throw new RuntimeException("根据领域工厂的使用规范，您的编码出现错误，错误如下:类异常" + aClass);
    }

}
